package zsd.reiview.experiment.crf;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import zsd.reiview.utility.StringUtility;
import zsd.review.split.IctSpliting;

import com.aliasi.crf.ChainCrfFeatureExtractor;
import com.aliasi.crf.ChainCrfFeatures;
import com.aliasi.util.CollectionUtils;
import com.aliasi.util.Counter;
import com.aliasi.util.ObjectToDoubleMap;

/**
 * @Title: CrfFeatureExtractor.java
 * @Package zsd.reiview.experiment.crf
 * @Description: TODO(添加描述)
 * @author 朱圣代
 * @date 2011-11-1 下午03:46:12
 * @version V1.0
 */
public class CrfFeatureExtractor implements ChainCrfFeatureExtractor<String>, Serializable {

	static Counter counter = new Counter(0);
	static SentiDictionay sentiDictionay;
	static IctSpliting ictSpliting = new IctSpliting();
	static boolean[] select;
	static double[] weigth;

	public CrfFeatureExtractor() {
		try {
			sentiDictionay = SentiDictionay.getInstance();
			select = CrfChunkerTest.select;
			weigth = CrfChunkerTest.getWeigth();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();

		} catch (IOException e) {
			e.printStackTrace();

		}
	}

	@Override
	public ChainCrfFeatures<String> extract(List<String> tokens, List<String> tags) {
		return new CrfChainCrfFeatures(tokens, tags);
	}

	static class CrfChainCrfFeatures extends ChainCrfFeatures<String> {
		List<String> tokens;
		List<String> tags;
		List<String> poss;
		List<String> sentis;

		public CrfChainCrfFeatures(List<String> tokens, List<String> tags) {
			super(tokens, tags);
			this.tokens = tokens;
			this.tags = tags;
			String sent = StringUtility.list2str(tokens);

			// poss = CrfCorpus.getPosList().get(sent).get(0);
			// sentis = CrfCorpus.getPosList().get(sent).get(1);
			sentis = new ArrayList<String>();
			for (int i = 0; i < tokens.size(); i++) {
				sentis.add(isSenti(i));
			}
			poss = new ArrayList<String>();
			HashMap<String, String> posHash = new HashMap<String, String>();
			List<String> tokList = ictSpliting.splitToWords(sent);
			List<String> posList = ictSpliting.getPosList();

			for (int i = 0; i < tokList.size(); i++) {
				posHash.put(tokList.get(i), posList.get(i));
			}
			for (int i = 0; i < tokens.size(); i++) {
				String pos = posHash.get(tokens);
				if (pos == null)
					pos = "x";
				poss.add(pos);
			}
		}

		int labledNum = 1;

		public void setLabledNum(int num) {
			labledNum = num;
		}

		@Override
		public Map<String, ? extends Number> edgeFeatures(int n, int k) {
			ObjectToDoubleMap<String> feats = new ObjectToDoubleMap<String>();
			// feats.set("PREV_TAG_" + tag(k), 1.0);
			// feats.set("PREV_TAG_TOKEN_CAT_" + tag(k) + "_" + poss.get(n - 1), 1.0);
			return feats;
		}

		public String tokenCat(int n) {

			String tok = token(n);
			if (tok.matches("[0-9\\.]+"))
				return "N";
			if (tok.matches("[A-Za-z]+"))
				return "L";

			if (n >= poss.size() - 1)
				return "X";
			if (poss.get(n).equals("w"))
				return "P";

			return "W";
		}

		@Override
		public Map<String, ? extends Number> nodeFeatures(int n) {
			ObjectToDoubleMap<String> feats = new ObjectToDoubleMap<String>();
			boolean bos = n == 0;
			boolean eos = (n + 1) >= numTokens();
			boolean bos2 = n < 2;
			boolean eos2 = (n + 2) >= numTokens();

			String tokenCat = tokenCat(n);
			String prevTokenCat = bos ? null : tokenCat(n - 1);
			String nextTokenCat = eos ? null : tokenCat(n + 1);

			String token = token(n);
			String prevToken = bos ? null : token(n - 1);
			String nextToken = eos ? null : token(n + 1);

			String posTag = poss.get(n);
			String prevPosTag = bos ? null : poss.get(n - 1);
			String nextPosTag = eos ? null : poss.get(n + 1);

			String senti = sentis.get(n);
			String prevSenti = bos ? null : sentis.get(n - 1);
			String nextSenti = eos ? null : sentis.get(n + 1);

			String prevSenti2 = bos2 ? null : sentis.get(n - 2);
			String nextSenti2 = eos2 ? null : sentis.get(n + 2);

			if (bos)
				feats.set("BOS", 1.0);
			if (eos)
				feats.set("EOS", 1.0);
			if (!bos && !eos)
				feats.set("!BOS!EOS", 1.0);

			if (select[0])
				feats.set("TOK_" + token, weigth[0]);
			if (!bos)
				if (select[1])
					feats.set("TOK_PREV_" + prevToken, weigth[1]);
			if (!eos)
				if (select[2])
					feats.set("TOK_NEXT_" + nextToken, weigth[2]);

			if (select[3])
				feats.set("TOK_CAT_" + tokenCat, weigth[3]);
			if (!bos)
				if (select[4])
					feats.set("TOK_CAT_PREV_" + prevTokenCat, weigth[4]);
			if (!eos)
				if (select[5])
					feats.set("TOK_CAT_NEXT_" + nextToken, weigth[5]);

			if (select[6])
				feats.set("POS_" + posTag, weigth[6]);
			if (!bos)
				if (select[7])
					feats.set("POS_PREV_" + prevPosTag, weigth[7]);
			if (!eos)
				if (select[8])
					feats.set("POS_NEXT_" + nextPosTag, weigth[8]);

			if (select[9])
				feats.set("SENT_" + senti, weigth[9]);
			if (!bos)
				if (select[10])
					feats.set("SENT_PREV_" + prevSenti, weigth[10]);
			if (!eos)
				if (select[11])
					feats.set("SENT_NEXT_" + nextSenti, weigth[11]);

			if (!bos2)
				if (select[12])
					feats.set("SENT_PREV_2_" + prevSenti2, weigth[12]);
			if (!eos2)
				if (select[13])
					feats.set("SENT_NEXT_2_" + nextSenti2, weigth[13]);

			return feats;
		}

		public String isSenti(int n) {
			String cString = sentiDictionay.findPhraseCat(token(n));
			return (cString.equals("B") || cString.equals("G")) ? "Y" : "N";
		}
	}
}
